#include "stdafx.h"
#include "ChessStatus.h"

#include "WinRate.h"

#include <CommonStringFunction.h>
#include <Common.h>

#include <IValue.h>

ChessStatus::ChessStatus(const vector<Point>& black, const vector<Point>& white, const ChessStatus::Color togo):_toGo(togo)
{
	//Initialize all colors.
	InitColors();

	//Add black and white to color.
	for (auto b : black)
	{
		_colors[b.X()][b.Y()] = Black;
	}
	for (auto w : white)
	{
		_colors[w.X()][w.Y()] = White;
	}

	//Compute hash code.
	_hash = ComputeHash();
}

ChessStatus::ChessStatus()
{
	InitColors();
}

ChessStatus::~ChessStatus()
{
	for (int i = 0; i < ChessSize; ++i)
	{
		delete[] _colors[i];
	}
	delete[] _colors;
}

std::string ChessStatus::GetHash() const
{
	return _hash;
}

void ChessStatus::UpdateWinRate(const ChessStatus* status, const double newVal)
{
	//Average new value and old value then update.
	ExperientialSystem::IValue* oldVal = NULL;
	my_assert(this->GetValue(status, oldVal));

	double oldWinrate = dynamic_cast<WinRate*>(oldVal)->GetWinRate();
	double averaged = (oldWinrate + newVal) / 2;

	auto_ptr<WinRate> newRate(new WinRate(averaged));
	my_assert(this->UpdateValue(status, newRate.get()));
}

bool ChessStatus::GetWinRate(const ChessStatus* nextStatus, double& winrate) const
{
	ExperientialSystem::IValue* value = NULL;
	if (GetValue(nextStatus, value))
	{
		winrate = dynamic_cast<WinRate*>(value)->GetWinRate();
		return true;
	}
	else
	{
		return false;
	}
}

vector<Point> ChessStatus::GetAllBlacks() const
{
	vector<Point> res;
	for (int i = 0; i < ChessSize; ++i)
	{
		for (int j = 0; j < ChessSize; ++j)
		{
			Color c = _colors[i][j];
			if (c == Black)
			{
				res.push_back(Point(i, j));
			}
		}
	}

	return res;
}

vector<Point> ChessStatus::GetAllWhites() const
{
	vector<Point> res;
	for (int i = 0; i < ChessSize; ++i)
	{
		for (int j = 0; j < ChessSize; ++j)
		{
			Color c = _colors[i][j];
			if (c == White)
			{
				res.push_back(Point(i, j));
			}
		}
	}

	return res;
}

vector<Point> ChessStatus::GetAllEmptys() const
{
	vector<Point> res;
	for (int i = 0; i < ChessSize; ++i)
	{
		for (int j = 0; j < ChessSize; ++j)
		{
			Color c = _colors[i][j];
			if (c == None)
			{
				res.push_back(Point(i, j));
			}
		}
	}

	return res;
}

void ChessStatus::Compare(const ChessStatus* other, vector<Point>& increBlack, vector<Point>& increWhite, vector<Point>& decreBlack, vector<Point>& decreWhite)
{
	Color** otherColor = other->_colors;

	for (int i = 0; i < ChessSize; ++i)
	{
		for (int j = 0; j < ChessSize; ++j)
		{
			Color meC = _colors[i][j];
			Color otherC = otherColor[i][j];
			Point pt(i, j);
			if (meC == Black)
			{
				if (otherC == None)
				{
					increBlack.push_back(pt);
				}
				else if (otherC == White)
				{
					increBlack.push_back(pt);
					decreWhite.push_back(pt);
				}
			}
			else if (meC == White)
			{
				if (otherC == None)
				{
					increWhite.push_back(pt);
				}
				else if (otherC == Black)
				{
					increWhite.push_back(pt);
					decreBlack.push_back(pt);
				}
			}
			else
			{
				if (otherC == White)
				{
					decreWhite.push_back(pt);
				}
				else if (otherC == Black)
				{
					decreBlack.push_back(pt);
				}
			}
		}
	}
}

void ChessStatus::Write(ofstream& out) const
{
	out << _toGo << " ";
	//Write colors.
	for (int i = 0; i < ChessSize; ++i)
	{
		for (int j = 0; j < ChessSize; ++j)
		{
			out << _colors[i][j] << " ";
		}
	}
}

void ChessStatus::Read(ifstream& in)
{
	int toGoInt;
	in >> toGoInt;
	_toGo = (Color)toGoInt;

	//Read colors.
	for (int i = 0; i < ChessSize; ++i)
	{
		for (int j = 0; j < ChessSize; ++j)
		{
			int cInt;
			in >> cInt;
			_colors[i][j] = (Color)cInt;
		}
	}

	_hash = ComputeHash();
}

void ChessStatus::InitColors()
{
	_colors = new Color*[ChessSize];
	for (int i = 0; i < ChessSize; ++i)
	{
		_colors[i] = new Color[ChessSize];
		for (int j = 0; j < ChessSize; ++j)
		{
			_colors[i][j] = None;
		}
	}
}

std::string ChessStatus::ComputeHash() const
{
	string rawHash = "";
	rawHash += CommonTool::ToString(_toGo);
	for (int i = 0; i < ChessSize; ++i)
	{
		for (int j = 0; j < ChessSize; ++j)
		{
			Color c = _colors[i][j];
			if (c != None)
			{
				string iStr = CommonTool::ToString(i);
				if (i < 10)
				{
					iStr = "0" + iStr;
				}
				string jStr = CommonTool::ToString(j);
				if (j < 10)
				{
					jStr = "0" + jStr;
				}

				rawHash += CommonTool::ToString(c) + iStr + jStr;
			}
		}
	}
	string res = CommonTool::GenerateHash(rawHash);
	return res;
}

void ChessStatus::SetWinRate(const ChessStatus* status, const double newVal)
{
	auto_ptr<WinRate> newRate(new WinRate(newVal));
	my_assert(this->UpdateValue(status, newRate.get()));
}

int ChessStatus::GetPieceCount() const
{
	int res = 0;
	for (int i = 0; i < ChessSize; ++i)
	{
		for (int j = 0; j < ChessSize; ++j)
		{
			Color c = _colors[i][j];
			if (c != None)
			{
				++res;
			}
		}
	}

	return res;
}
